/******************************************************************
 * Closure is build on the idea of scope and having inner functions
 * have access to the outer function's variable and parameters even
 * after the life-time of the outter function.
 * This Javascript program should be run using node.js 
 * ****************************************************************/

// A simple example

var myObject = function(){ //This is the outter function
    var fvalue = 0;   //Ths variable belongs to the outer function.

    return {
        //addValue works like a method that modify the fvalue.
        addValue: function(num){
            fvalue += (typeof num === 'number') ? num : 0;
        },
        //getValue returns the fvalue to the caller.
        getValue: function(){
            return fvalue;
        }
    };
}(); //Invoking the outter function creates the closure.
//There is no way to access fvalue from outside the scope 

console.log("Initial value of myObject = "+myObject.getValue());
myObject.addValue(10);
console.log("After adding 10 to myObject = "+myObject.getValue());

/*******************************************************************
 * Each closure have a copy of the object.
 ******************************************************************/

var state = function(initState, j){
    var i = 0;
    return {
        setState: function(newState){
            initState = newState;
        },

        getState: function(){            
            return initState;
        },

        incI: function(){
            return ++i;
        },

        incJ: function(){
            return ++j;
        }
    };
}

console.log("Create myState with \"starting\"");
var myState = state("starting", 0); //This invoke the state(..)
console.log("myState is now ... "+ myState.getState());
console.log("Create otherState with \"ending\"");
var myOtherState = state("ending", 10);
console.log("myOtherState is now ... "+myOtherState.getState());
console.log("myState is now ... "+ myState.getState());
console.log("Change myState to \"working\"");
myState.setState("working");
console.log("myOtherState is now ... "+myOtherState.getState());
console.log("myState is now ... "+ myState.getState());
console.log("Calling incI from myState value="+myState.incI());
console.log("Calling incI from myOtherState value="+myOtherState.incI());
console.log("Calling incJ from myState value="+myState.incJ());
console.log("Calling incJ from myOtherState value="+myOtherState.incJ());

/********************************************************************
 * However, be aware that the copy is only made on invoke.
 * *******************************************************************/

var funArray = new Array(10); //Create an object which can hold 10 objects

var assignFuncs = function(farray){
    var i;
    for( i = 0; i < farray.length; i+=1){
        //In order to have i visible
        //console.log must be called from here.
        farray[i] = function(){
            console.log(i); //This function is only invoked later.
            //but it still have access to var i with its latest value.
            return i;
        }
    }
}

assignFuncs(funArray);

var i;
for(i = 0; i < funArray.length; i++)
{
    console.log("Calling funArray i="+i+" prints "+funArray[i]());
}

